<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>08_单线程-异步代码如何执行</title>
  <!-- 
  在 JavaScript 中，异步代码的执行是通过事件循环机制（Event Loop）来管理的。由于 JavaScript 是单线程的，这意味着它一次只能执行一个任务。
  1. 单线程与异步
  - JavaScript 是单线程的，意味着它在任何时刻只能执行一个操作。
  - 为了处理异步操作（如网络请求、定时器等），JavaScript 使用事件循环机制来允许非阻塞的操作。

  2. 执行栈（Call Stack）
  - 执行栈用于管理函数调用。当一个函数被调用时，它会被推入栈中，执行完成后会被弹出。
  - 同步代码会在执行栈中依次执行，遵循后进先出（LIFO）的原则。

  3. 异步操作与回调
  - 当遇到异步操作（例如  `setTimeout` 、 `fetch`  等），JavaScript 会将这些操作交给浏览器的 Web APIs。
  - 异步操作完成后，回调函数会被放入任务队列（Task Queue）。

  4. 事件循环（Event Loop）
  - 事件循环负责监控执行栈和任务队列。当执行栈为空时，事件循环会从任务队列中取出一个任务并将其推入执行栈中执行。
  - 这使得 JavaScript 能够在执行其他代码的同时，等待异步操作的完成。

  5. 微任务与宏任务
  - 在任务队列中，有两种类型的任务：微任务（Microtasks）和宏任务（Macrotasks）。
    - 微任务包括 Promise 的  `.then()`  回调，优先级高于宏任务。
    - 宏任务包括  `setTimeout` 、 `setInterval`  等。

  - 微任务会在当前任务执行完成后立即执行，而宏任务会在微任务队列清空后再执行。

  6. 示例代码
  以下是一个示例，展示了异步代码的执行顺序：
  console.log("Start");

  setTimeout(() => {
      console.log("Timeout");
  }, 0);

  Promise.resolve().then(() => {
      console.log("Promise");
  });

  console.log("End");
  输出顺序：
  Start
  End
  Promise
  Timeout
  
  7. 总结
  - JavaScript 的异步代码执行依赖于事件循环机制，使得单线程能够处理非阻塞的操作。
  - 执行栈用于管理同步代码的执行，而异步操作的回调会被放入任务队列。
  - 事件循环监控执行栈和任务队列，确保异步操作在合适的时机执行。
  - 微任务优先级高于宏任务，微任务会在当前执行上下文结束后立即执行。
  -->
</head>
<body>

  <button>按钮</button>

  <script>
    const btn = document.querySelector('button')
    btn.addEventListener('click', () => {
      console.log('点击了按钮')
    })

    console.log("hello start");
    let i = 0;
    i = i + 1;

    // 异步代码
    setTimeout(() => {
      console.log('定时器执行了')
    }, 0)

    console.log('代码执行完毕')

  </script>
  
</body>
</html>